package main

import (
	"fmt"
	"github.com/ngaut/log"
	"strconv"
	"strings"
	"time"
	"github.com/petermattis/goid"
)
import "sync"
import "runtime"

func Add(x,y int) {
	z := x+y
	fmt.Println(z)
}

//还没来得及执行，main就退出了
func t1() {
	for i:=0; i<10; i++ {
		go Add(i,i)
	}
}

var counter2 int = 0
func Count(lock *sync.Mutex) {
	lock.Lock()
	counter2++
	fmt.Println(counter2)
	lock.Unlock()
}

//使用共享内存进行通信，也得使用锁
func t2() {
	lock := &sync.Mutex{}
	for i:=0; i<10; i++ {
		go Add(i,i)
	}
	for {
		lock.Lock()
		c := counter2
		lock.Unlock()
		runtime.Gosched()
		if c >= 10 {
			break
		}
	}
}


/////////////////// 使用channel
func t3() {
	//声明channel
	var ch chan int
	var m map[string] chan bool
	var m2 chan map[string] bool
	fmt.Println(ch,m,m2)

	//定义channel
	ch2 := make(chan int) //声明加初始化

	var c1 chan int
	var c2 chan<- float64 //只支持写的channel
	var c3 <-chan int //只支持读的channel
	c5 := <-chan int (ch2) //单向读取channel
	c6 := chan<- int (ch2) //单向写入channel
	fmt.Println(ch2, c1,c2,c3,c5,c6)

	//判断channel是否已经关闭
}

func GoID(i int) int {
	var buf [64]byte
	n := runtime.Stack(buf[:], false)
	log.Debugf("%d buf: %s", i, string(buf[:n]))
	idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
	id, err := strconv.Atoi(idField)
	if err != nil {
		panic(fmt.Sprintf("cannot get goroutine id: %v", err))
	}
	return id
}
// https://colobu.com/2016/04/01/how-to-get-goroutine-id/
func t_get_goroutine_id() {
	fmt.Println("main", GoID(-1))
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		i := i
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Println(i, GoID(i))
		}()
	}
	wg.Wait()
}

// https://colobu.com/2017/08/04/talk-about-getting-goroutine-id-again/
func t_use_goid_lib() {
	for i := 0; i < 3; i++ {
		go func() {
			for j := 0; j < 3; j++ {
				log.Infof("[#%d] %d", goid.Get(), j)
				time.Sleep(10e9)
			}
		}()
	}
	// error: all goroutines are asleep - deadlock!
	// https://www.cnblogs.com/ghj1976/p/4295013.html
	select {}
}

func t_all_routines_deadlock_error() {
	channel := make(chan string, 2)

	fmt.Println("1")
	channel <- "h1"
	fmt.Println("2")
	channel <- "w2"
	fmt.Println("3")
	channel <- "c3"    // 执行到这一步，直接报 error
	fmt.Println("...")
	msg1 := <-channel
	fmt.Println(msg1)
}

func t_busy_loop() {
	ch1 := make(chan int, 1)
	ch2 := make(chan int ,1)
	for {
		select {
		case <- ch1:
			fmt.Println("ch1 pop")
		case <- ch2:
			fmt.Println("ch2 pop")
		}
	}
}

func main() {
	go t_busy_loop()
	time.Sleep(time.Second * 10)
	//t_all_routines_deadlock_error()
	//t_use_goid_lib()
	//t_get_goroutine_id()
	//t3()//竟然死锁了？？
}